﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using Xceed.Silverlight.Data.Stats;
using Xceed.Silverlight.Data.Utils;

namespace Xceed.Silverlight.Data
{
  public class ParentDataSourceProvider : DataSourceProvider, IBufferConfigurable
  {
    #region Constructor

    internal ParentDataSourceProvider( DataSourceProvider dataSourceProvider )
    {
      if( dataSourceProvider == null )
        throw new ArgumentNullException( "dataSourceProvider" );

      m_childDataSourceProvider = dataSourceProvider;
      m_childDataSourceChangedEventListener = new DataSourceChangedEventListener( this.OnChildDataSourceChanged );

      DataSourceChangedEventManager.AddListener( dataSourceProvider, m_childDataSourceChangedEventListener );

      if( !( dataSourceProvider is IBufferConfigurable ) )
      {
        m_bufferConfiguration = ( this.IsBufferingAllowed )
                                  ? new DynamicBufferConfiguration()
                                  : null;
      }
    }

    #endregion

    #region CanCount Property

    public override bool CanCount
    {
      get
      {
        return m_childDataSourceProvider.CanCount;
      }
    }

    #endregion

    #region CanGroupCount Property

    public override bool CanGroupCount
    {
      get
      {
        return m_childDataSourceProvider.CanGroupCount;
      }
    }

    #endregion

    #region CanCalculateStats Property

    public override bool CanCalculateStats
    {
      get
      {
        return m_childDataSourceProvider.CanCalculateStats;
      }
    }

    #endregion

    #region CanFilter Property

    public override bool CanFilter
    {
      get
      {
        return m_childDataSourceProvider.CanFilter;
      }
    }

    #endregion

    #region CanJump Property

    public override bool CanJump
    {
      get
      {
        return m_childDataSourceProvider.CanJump;
      }
    }

    #endregion

    #region CanFilterGroup Property

    public override bool CanFilterGroup
    {
      get
      {
        return m_childDataSourceProvider.CanFilterGroup;
      }
    }

    #endregion

    #region CanJumpToItem Property

    public override bool CanJumpToItem
    {
      get
      {
        return m_childDataSourceProvider.CanJumpToItem;
      }
    }

    #endregion

    #region CanSkip Property

    public override bool CanSkip
    {
      get
      {
        return m_childDataSourceProvider.CanSkip;
      }
    }

    #endregion

    #region BufferConfiguration Property

    public BufferConfiguration BufferConfiguration
    {
      get
      {
        IBufferConfigurable bufferConfigurable = m_childDataSourceProvider as IBufferConfigurable;

        if( bufferConfigurable != null )
        {
          return bufferConfigurable.BufferConfiguration;
        }
        else
        {
          return m_bufferConfiguration;
        }
      }
      set
      {
        IBufferConfigurable bufferConfigurable = m_childDataSourceProvider as IBufferConfigurable;

        if( bufferConfigurable != null )
        {
          bufferConfigurable.BufferConfiguration = value;
        }
        else if( value != m_bufferConfiguration )
        {
          m_bufferConfiguration = value;
        }
      }
    }

    private BufferConfiguration m_bufferConfiguration; //null

    #endregion

    #region ChildDataSourceProvider Protected Property

    protected DataSourceProvider ChildDataSourceProvider
    {
      get
      {
        return m_childDataSourceProvider;
      }
    }

    #endregion

    #region ElementType Protected Internal Property

    protected internal override Type ElementType
    {
      get
      {
        return m_childDataSourceProvider.ElementType;
      }
    }

    #endregion

    #region CanSort Internal Property

    internal override bool CanSort
    {
      get
      {
        return m_childDataSourceProvider.CanSort;
      }
    }

    #endregion

    #region CanFilterPredicate Internal Property

    internal override bool CanFilterPredicate
    {
      get
      {
        return m_childDataSourceProvider.CanFilterPredicate;
      }
    }

    #endregion

    #region CanJumpToDeletedItem Internal Property

    internal override bool CanJumpToDeletedItem
    {
      get
      {
        return m_childDataSourceProvider.CanJumpToDeletedItem;
      }
    }

    #endregion

    #region PrimaryKeyInfo Internal Property

    internal new IEnumerable<SortDescription> PrimaryKeyInfo
    {
      get
      {
        return m_childDataSourceProvider.PrimaryKeyInfo;
      }
    }

    #endregion

    #region IsAsynchronous Internal Property

    internal override bool IsAsynchronous
    {
      get
      {
        return m_childDataSourceProvider.IsAsynchronous;
      }
    }

    #endregion

    #region IsBufferingAllowed Internal Property

    internal override bool IsBufferingAllowed
    {
      get
      {
        return m_childDataSourceProvider.IsBufferingAllowed;
      }
    }

    #endregion

    #region IsCachingAllowed Internal Property

    internal override bool IsCachingAllowed
    {
      get
      {
        return m_childDataSourceProvider.IsCachingAllowed;
      }
    }

    #endregion

    #region IsPrimaryKeyVolatile Internal Property

    internal override bool IsPrimaryKeyVolatile
    {
      get
      {
        return m_childDataSourceProvider.IsPrimaryKeyVolatile;
      }
    }

    #endregion

    protected override IEnumerable<SortDescription> GetPrimaryKeyInfo()
    {
      return m_childDataSourceProvider.PrimaryKeyInfo;
    }

    protected override void Initialize()
    {
      m_childDataSourceProvider.Init( this.Dispatcher );
    }

    protected virtual void OnChildDataSourceChanged( DataSourceChangedEventArgs e )
    {
      this.OnDataSourceChanged( e );
    }

    protected override void OnInvalidateData()
    {
    }

    protected override void OnInvalidateDataObjects( IEnumerable<ItemChangedDescription> itemsChanged )
    {
    }

    protected override void OnDataObjectsAdded( IEnumerable<object> itemsAdded )
    {
      m_childDataSourceProvider.NotifyItemsAdded( itemsAdded );
    }

    protected override void OnDataObjectsRemoved( IEnumerable<object> itemsRemoved )
    {
      m_childDataSourceProvider.NotifyItemsRemoved( itemsRemoved );
    }

    internal override IAsyncResult BeginExecuteCountQueryCore( 
      CountQueryParameters queryParameters, 
      AsyncCallback callback, 
      object state )
    {
      return m_childDataSourceProvider.BeginExecuteCountQueryInternal( queryParameters, callback, state );
    }

    internal override CountQueryResult EndExecuteCountQueryCore( IAsyncResult asyncResult )
    {
      return m_childDataSourceProvider.EndExecuteCountQueryInternal( asyncResult );
    }

    internal override IAsyncResult BeginExecuteDataQueryCore( 
      DataQueryParameters queryParameters, 
      AsyncCallback callback, 
      object state )
    {
      return m_childDataSourceProvider.BeginExecuteDataQueryInternal( queryParameters, callback, state );
    }

    internal override DataQueryResult EndExecuteDataQueryCore( IAsyncResult asyncResult )
    {
      return m_childDataSourceProvider.EndExecuteDataQueryInternal( asyncResult );
    }

    internal override IAsyncResult BeginExecuteGroupCountQueryCore( 
      GroupCountQueryParameters queryParameters, 
      AsyncCallback callback, 
      object state )
    {
      return m_childDataSourceProvider.BeginExecuteGroupCountQueryInternal( queryParameters, callback, state );
    }

    internal override GroupCountQueryResult EndExecuteGroupCountQueryCore( IAsyncResult asyncResult )
    {
      return m_childDataSourceProvider.EndExecuteGroupCountQueryInternal( asyncResult );
    }

    internal override IAsyncResult BeginExecuteStatQueryCore(
      StatQueryParameters queryParameters,
      AsyncCallback callback,
      object state )
    {
      return m_childDataSourceProvider.BeginExecuteStatQueryInternal( queryParameters, callback, state );
    }

    internal override StatQueryResult EndExecuteStatQueryCore( IAsyncResult asyncResult )
    {
      return m_childDataSourceProvider.EndExecuteStatQueryInternal( asyncResult );
    }

    internal override IEnumerable<FilterOperator> SupportedFilterOperators( Type dataType )
    {
      return m_childDataSourceProvider.SupportedFilterOperators( dataType );
    }

    internal override IEnumerable<Type> SupportedStatFunctions( Type dataType )
    {
      return m_childDataSourceProvider.SupportedStatFunctions( dataType );
    }

    internal override bool IsStatFunctionSupportedNatively( StatFunction statFunction )
    {
      return m_childDataSourceProvider.IsStatFunctionSupportedNatively( statFunction );
    }

    internal override bool IsSortOrderSupported( IEnumerable<SortDescription> sortOrder )
    {
      return m_childDataSourceProvider.IsSortOrderSupported( sortOrder );
    }

    internal override bool FindElementMemberType( string memberName, out Type type )
    {
      return m_childDataSourceProvider.FindElementMemberType( memberName, out type );
    }

    internal override bool CanJumpTo( IEnumerable<SortDescription> properties )
    {
      if( !this.CanJump )
        return false;

      return m_childDataSourceProvider.CanJumpTo( properties );
    }

    internal override int GetPageSize()
    {
      int pageSize = base.GetPageSize();
      int childPageSize = m_childDataSourceProvider.GetPageSize();

      if( pageSize > 0 && childPageSize > 0 )
        return Math.Min( pageSize, childPageSize );

      return ( pageSize <= 0 ) ? childPageSize : pageSize;
    }

    internal sealed override void CheckIfStatFunctionIsInCalculation( StatFunction statFunction )
    {
      // The child DataSourceProvider will do the check.
    }

    internal sealed override void SetStatFunctionCalculationState(
      StatFunction statFunction,
      bool inCalculation )
    {
      // The child DataSourceProvider will do the job.
    }

    internal override void InvalidateData()
    {
      m_childDataSourceProvider.InvalidateData();
    }

    internal override void InvalidateDataItem( IEnumerable<ItemChangedDescription> itemsChanged )
    {
      m_childDataSourceProvider.InvalidateDataItem( itemsChanged );
    }

    internal override bool TryWrapDataObject( object item, out RawDataItem dataItem )
    {
      return m_childDataSourceProvider.TryWrapDataObject( item, out dataItem );
    }

    internal override bool TryUnwrapDataObject( RawDataItem dataItem, out object item )
    {
      return m_childDataSourceProvider.TryUnwrapDataObject( dataItem, out item );
    }

    internal override bool TryUnwrapLayer( RawDataItem dataItem, out object item )
    {
      return m_childDataSourceProvider.TryUnwrapLayer( dataItem, out item );
    }

    #region Private Fields

    private DataSourceProvider m_childDataSourceProvider;
    private DataSourceChangedEventListener m_childDataSourceChangedEventListener;

    #endregion

    #region Private DataSourceChangedEventListener Nested Type

    private class DataSourceChangedEventListener : ISLWeakEventListener
    {
      internal DataSourceChangedEventListener( Action<DataSourceChangedEventArgs> dataSourceChangedAction )
      {
        m_dataSourceChangedAction = dataSourceChangedAction;
      }

      bool ISLWeakEventListener.ReceiveWeakEvent( Type managerType, object sender, EventArgs e )
      {
        if( managerType == typeof( DataSourceChangedEventManager ) )
        {
          DataSourceChangedEventArgs dataSourceChangedEventArgs = e as DataSourceChangedEventArgs;
          if( dataSourceChangedEventArgs != null )
          {
            m_dataSourceChangedAction.Invoke( dataSourceChangedEventArgs );
            return true;
          }
        }

        return false;
      }

      private Action<DataSourceChangedEventArgs> m_dataSourceChangedAction;
    }

    #endregion
  }
}
